
#include <unistd.h>
#include <fcntl.h>

#include "glog/logging.h"
#include "real_fs_operations.h"

ssize_t real_read(int fd, char* buf, ssize_t size) {
    ssize_t amt_needed = size;
    ssize_t amt_read = 0;
    
    while (amt_needed > 0) {
        ssize_t cur_read = read(fd, buf, amt_needed);
        if (cur_read == -1) {
            if (errno == EINTR) continue;
            return -errno;
        }
        if (cur_read == 0) {
            // Subsequent read attempt yielded no progress. We're done!
            break;
        }
        amt_needed -= cur_read;
        amt_read += cur_read;
        buf += cur_read;
    }
    CHECK(amt_needed >= 0);

    return amt_read;
}

ssize_t real_write(int fd, const char* buf, ssize_t size) {
    ssize_t amt_left = size;

    while (amt_left > 0) {
        ssize_t cur_write = write(fd, buf, amt_left);
        if (cur_write == -1) {
            if (errno == EINTR) continue;
            return -errno;
        }
        if (cur_write == 0) {
            // Subsequent write attempt yielded no progress. Quit.
            return -ECANCELED;
        }
        amt_left -= cur_write;
        buf += cur_write;
    }
    CHECK(amt_left >= 0);

    return size;
}

int real_open(const char* path, int flags) {
    if (flags | O_WRONLY) {
        flags &= ~O_WRONLY;
        flags |= O_RDWR;
    }
    return open(path, flags);
}

int real_creat(const char* path, int flags, mode_t mode) {
    if (flags | O_WRONLY) {
        flags &= ~O_WRONLY;
        flags |= O_RDWR;
    }
    flags |= O_TRUNC;
    return open(path, flags, mode);
}
